/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  							 abstract_script_expression.h

	$Header: /heroes4/abstract_script_expression.h $

	$NoKeywords: $

 ************************************************************************/

#if !defined( ABSTRACT_SCRIPT_EXPRESSION_H_INCLUDED )
#define ABSTRACT_SCRIPT_EXPRESSION_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <iosfwd>
#include <memory>

#include "counted_ptr.h"
#include "script_expression_type.h"
#include "script_context_args.h"
#include "streambuf_operators.h"
#include "uncopyable.h"

// --------------------------------------------------------------------------
// t_abstract_script_expression_factory class template
// --------------------------------------------------------------------------

template < typename t_abstract_expression >
class t_abstract_script_expression_factory : private t_uncopyable
{
public:
	// Types
	typedef t_counted_ptr< t_abstract_expression >	t_create_ptr;

	// Member functions
	virtual t_create_ptr	create() const = 0;

protected:
	// Destructor
	~t_abstract_script_expression_factory() {}
};

// --------------------------------------------------------------------------
// t_abstract_script_expression_base class template
// --------------------------------------------------------------------------

class t_adventure_object;
class t_adventure_map;
class t_hero;
class t_town;
class t_army;

template < typename t_derived, typename t_type_arg, typename t_result_arg >
class t_abstract_script_expression_base : public t_counted_object
{
public:
	// Types
	typedef t_counted_ptr< t_derived >							t_clone_ptr;
	typedef t_abstract_script_expression_factory< t_derived >	t_factory;
	typedef t_counted_ptr< t_derived >							t_reconstruct_ptr;
	typedef t_result_arg										t_result;
	typedef t_type_arg											t_type;

	// Destructor
	virtual ~t_abstract_script_expression_base() {};

	// Member functions
	virtual t_clone_ptr	clone() const = 0;

	virtual t_result	evaluate(t_expression_context_hero const& context) const;
	virtual t_result	evaluate(t_expression_context_town const& context) const;
	virtual t_result	evaluate(t_expression_context_object const& context) const;
	virtual t_result	evaluate(t_expression_context_army const& context) const;
	virtual t_result	evaluate(t_expression_context_global const& context) const = 0;

	virtual t_type		get_type() const = 0;

	virtual bool		read( std::streambuf& stream, int version ) = 0;
	virtual bool		read_from_map(
							std::streambuf &	stream,
							int					format_version ) = 0;
	virtual bool		write( std::streambuf& stream ) const = 0;
};

template < typename t_derived, typename t_type_arg, typename t_result_arg >
typename t_abstract_script_expression_base< t_derived, t_type_arg, t_result_arg >::t_result 
t_abstract_script_expression_base< t_derived, t_type_arg, t_result_arg >::evaluate(t_expression_context_hero const& context) const
{
	return evaluate(t_expression_context_global(context.map));
}

template < typename t_derived, typename t_type_arg, typename t_result_arg >
typename t_abstract_script_expression_base< t_derived, t_type_arg, t_result_arg >::t_result 
t_abstract_script_expression_base< t_derived, t_type_arg, t_result_arg >::evaluate(t_expression_context_town const& context) const
{
	return evaluate(t_expression_context_global(context.map));
}

template < typename t_derived, typename t_type_arg, typename t_result_arg >
typename t_abstract_script_expression_base< t_derived, t_type_arg, t_result_arg >::t_result 
t_abstract_script_expression_base< t_derived, t_type_arg, t_result_arg >::evaluate(t_expression_context_object const& context) const
{
	return evaluate(t_expression_context_global(context.map));
}

template < typename t_derived, typename t_type_arg, typename t_result_arg >
typename t_abstract_script_expression_base< t_derived, t_type_arg, t_result_arg >::t_result 
t_abstract_script_expression_base< t_derived, t_type_arg, t_result_arg >::evaluate(t_expression_context_army const& context) const
{
	return evaluate(t_expression_context_global(context.map));
}

template < typename t_derived, typename t_type_arg, typename t_result_arg >
bool t_abstract_script_expression_base< t_derived, t_type_arg, t_result_arg >::write( std::streambuf& stream ) const
{
	return write_string16(stream, get_keyword(get_type()));
}

template < typename t_derived, typename t_type_arg, typename t_result_arg >
bool t_abstract_script_expression_base< t_derived, t_type_arg, t_result_arg >::read( std::streambuf& stream, int version )
{
	return true;
}

// --------------------------------------------------------------------------
// t_script_numeric_expression class template - Intended to be specialized
// for each numeric expression type
// --------------------------------------------------------------------------

template < t_script_numeric_expression_type k_type >
class t_script_numeric_expression {};

// --------------------------------------------------------------------------
// t_abstract_script_numeric_expression class
// --------------------------------------------------------------------------

class t_abstract_script_numeric_expression
	:	public	t_abstract_script_expression_base<
					t_abstract_script_numeric_expression,
					t_script_numeric_expression_type,
					int >
{
public:
	// Static member functions
	static t_reconstruct_ptr	reconstruct( std::streambuf& stream, int version );
	static t_reconstruct_ptr	reconstruct_from_map(
									std::streambuf &	stream );
	static t_reconstruct_ptr	reconstruct_from_map(
									std::streambuf &	stream,
									int					format_version );
	static void					register_factory(
									t_type				type,
									t_factory const &	factory );
};

// --------------------------------------------------------------------------
// t_script_numeric_expresion_factory class template
// --------------------------------------------------------------------------

template < t_script_numeric_expression_type k_type >
class t_script_numeric_expression_factory
	:	public t_abstract_script_numeric_expression::t_factory
{
public:
	// Types
	typedef t_script_numeric_expression< k_type >	t_expression;

	// Constructor
	t_script_numeric_expression_factory();

	// Member functions
	virtual t_create_ptr	create() const;
};

// --------------------------------------------------------------------------
// t_script_numeric_expresion_factory members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_numeric_expression_type k_type >
t_script_numeric_expression_factory< k_type >::t_script_numeric_expression_factory()
{
	t_abstract_script_numeric_expression::register_factory( k_type, *this );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_numeric_expression_type k_type >
typename t_script_numeric_expression_factory< k_type >::t_create_ptr
t_script_numeric_expression_factory< k_type >::create() const
{
	return t_create_ptr( new t_expression );
}

// --------------------------------------------------------------------------
// t_script_numeric_expression_base class template
// --------------------------------------------------------------------------

template < t_script_numeric_expression_type k_type, typename t_base >
class t_script_numeric_expression_base : public t_base
{
public:
	// Types
	typedef typename t_base::t_clone_ptr		t_clone_ptr;
	typedef t_script_numeric_expression_type	t_type;

	// Member functions
	virtual t_clone_ptr	clone() const;
	virtual t_type		get_type() const;

private:
	// Static data members
	static t_script_numeric_expression_factory< k_type > const k_factory;
};

// --------------------------------------------------------------------------
// t_script_numeric_expression_base members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_numeric_expression_type k_type, typename t_base >
t_script_numeric_expression_factory< k_type > const t_script_numeric_expression_base< k_type, t_base >::k_factory;

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_numeric_expression_type k_type, typename t_base >
typename t_script_numeric_expression_base< k_type, t_base >::t_clone_ptr
t_script_numeric_expression_base< k_type, t_base >::clone() const
{
	typedef t_script_numeric_expression< k_type > t_actual;
	assert( dynamic_cast< t_actual const * >( this ) != 0 );
	return t_clone_ptr( new t_actual( static_cast< t_actual const & >( *this ) ) );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_numeric_expression_type k_type, typename t_base >
typename t_script_numeric_expression_base< k_type, t_base >::t_type
t_script_numeric_expression_base< k_type, t_base >::get_type() const
{
	// Force the instantiation of the factory
	&k_factory;
	return k_type;
}

// --------------------------------------------------------------------------
// SPECIALIZE_SCRIPT_NUMERIC_EXPRESSION() macro - used to create
// specializations of the t_script_numeric_expression<> class template from
// t_abstract_script_numeric_expression derived classes
// --------------------------------------------------------------------------

#define SPECIALIZE_SCRIPT_NUMERIC_EXPRESSION( k_type, t_base )	\
template <>														\
class t_script_numeric_expression< k_type >						\
	:	public t_script_numeric_expression_base< k_type, t_base > {}

// --------------------------------------------------------------------------
// t_script_boolean_expression class template - Intended to be specialized
// for each boolean expression type
// --------------------------------------------------------------------------

template < t_script_boolean_expression_type k_type >
class t_script_boolean_expression {};

// --------------------------------------------------------------------------
// t_abstract_script_boolean_expression class
// --------------------------------------------------------------------------

class t_abstract_script_boolean_expression
	:	public	t_abstract_script_expression_base<
					t_abstract_script_boolean_expression,
					t_script_boolean_expression_type,
					bool >
{
public:
	// Static member functions
	static t_reconstruct_ptr	reconstruct( std::streambuf& stream, int version );
	static t_reconstruct_ptr	reconstruct_from_map(
									std::streambuf &	stream );
	static t_reconstruct_ptr	reconstruct_from_map(
									std::streambuf &	stream,
									int					format_version );
	static void					register_factory(
									t_type				type,
									t_factory const &	factory );
};

// --------------------------------------------------------------------------
// t_script_boolean_expresion_factory class template
// --------------------------------------------------------------------------

template < t_script_boolean_expression_type k_type >
class t_script_boolean_expression_factory
	:	public t_abstract_script_boolean_expression::t_factory
{
public:
	// Types
	typedef t_script_boolean_expression< k_type >	t_expression;

	// Constructor
	t_script_boolean_expression_factory();

	// Member functions
	virtual t_create_ptr	create() const;
};

// --------------------------------------------------------------------------
// t_script_boolean_expresion_factory members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_boolean_expression_type k_type >
t_script_boolean_expression_factory< k_type >::t_script_boolean_expression_factory()
{
	t_abstract_script_boolean_expression::register_factory( k_type, *this );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_boolean_expression_type k_type >
typename t_script_boolean_expression_factory< k_type >::t_create_ptr
t_script_boolean_expression_factory< k_type >::create() const
{
	return t_create_ptr( new t_expression );
}

// --------------------------------------------------------------------------
// t_script_boolean_expression_base class template
// --------------------------------------------------------------------------

template < t_script_boolean_expression_type k_type, typename t_base >
class t_script_boolean_expression_base : public t_base
{
public:
	// Types
	typedef typename t_base::t_clone_ptr		t_clone_ptr;
	typedef t_script_boolean_expression_type	t_type;

	// Member functions
	virtual t_clone_ptr	clone() const;
	virtual t_type		get_type() const;

private:
	// Static data members
	static t_script_boolean_expression_factory< k_type > const k_factory;
};

// --------------------------------------------------------------------------
// t_script_boolean_expression_base members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_boolean_expression_type k_type, typename t_base >
t_script_boolean_expression_factory< k_type > const t_script_boolean_expression_base< k_type, t_base >::k_factory;

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_boolean_expression_type k_type, typename t_base >
typename t_script_boolean_expression_base< k_type, t_base >::t_clone_ptr
t_script_boolean_expression_base< k_type, t_base >::clone() const
{
	typedef t_script_boolean_expression< k_type > t_actual;
	assert( dynamic_cast< t_actual const * >( this ) != 0 );
	return t_clone_ptr( new t_actual( static_cast< t_actual const & >( *this ) ) );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_boolean_expression_type k_type, typename t_base >
typename t_script_boolean_expression_base< k_type, t_base >::t_type
t_script_boolean_expression_base< k_type, t_base >::get_type() const
{
	// Force the instantiation of the factory
	&k_factory;
	return k_type;
}

// --------------------------------------------------------------------------
// SPECIALIZE_SCRIPT_BOOLEAN_EXPRESSION() macro - used to create
// specializations of the t_script_boolean_expression<> class template from
// t_abstract_script_boolean_expression derived classes
// --------------------------------------------------------------------------

#define SPECIALIZE_SCRIPT_BOOLEAN_EXPRESSION( k_type, t_base )	\
template <>														\
class t_script_boolean_expression< k_type >						\
	:	public t_script_boolean_expression_base< k_type, t_base > {}

#endif // !defined( ABSTRACT_SCRIPT_EXPRESSION_H_INCLUDED )
